package com.market.plus.core.dao.jpa;

import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.springframework.dao.DataAccessException;
import org.springframework.orm.jpa.EntityManagerFactoryUtils;

import com.market.plus.core.domain.Persistable;

public abstract class AbstractJpaDao<T> {
   private Class< T > clazz;
   
   @PersistenceContext(unitName="marketPU")
   EntityManager entityManager;
   
   public void setClazz( final Class< T > clazzToSet ){
      this.clazz = clazzToSet;
   }
   
   public T findById( final Long id ){
      return entityManager.find( clazz, id );
   }

   public void save( final T entity ){
      if(((Persistable) entity).getId() == null) {
         entityManager.persist( entity );
      }
      else {
         entityManager.merge( entity );
      }
   }

   public void remove( final T entity ){
      entityManager.remove( entity );
   }

   public void remove( final Long entityId ){
      final T entity = findById( entityId );
      remove( entity );
   }

   @SuppressWarnings("rawtypes")
   public List findByNamedQuery(String queryName) throws DataAccessException {
      return findByNamedQuery(queryName, (Object[]) null);
   }

   @SuppressWarnings("rawtypes")
   public List findByNamedQuery(final String queryName, final Object... values) throws DataAccessException {
      Query queryObject = entityManager.createNamedQuery(queryName);
      prepareQuery(queryObject);
      if (values != null) {
         for (int i = 0; i < values.length; i++) {
            queryObject.setParameter(i + 1, values[i]);
         }
      }
      return queryObject.getResultList();
   }

   @SuppressWarnings("rawtypes")
   public List findByNamedQueryAndNamedParams(final String queryName, final Map<String, ?> params) throws DataAccessException {
      Query queryObject = entityManager.createNamedQuery(queryName);
      prepareQuery(queryObject);
      if (params != null) {
         for (Map.Entry<String, ?> entry : params.entrySet()) {
            queryObject.setParameter(entry.getKey(), entry.getValue());
         }
      }
      return queryObject.getResultList();
   }

   @SuppressWarnings("rawtypes")
   public List findByNativeQueryAndNamedParams(final String query, final Map<String, ?> params) throws DataAccessException {
      Query queryObject = entityManager.createNativeQuery(query, clazz);
      prepareQuery(queryObject);
      if (params != null) {
         for (Map.Entry<String, ?> entry : params.entrySet()) {
            queryObject.setParameter(entry.getKey(), entry.getValue());
         }
      }
      return queryObject.getResultList();
   }

   public void prepareQuery(Query query) {
      EntityManagerFactory emf = entityManager.getEntityManagerFactory();
      if (emf != null) {
         EntityManagerFactoryUtils.applyTransactionTimeout(query, emf);
      }
   }
}
